/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-08-26     86191       LCD软件SPI基础版
 * 2025-08-29     86191       新增ST7735 ID读取与显示功能
 * 2025-08-31     86191       适配128×128分辨率显示屏
 * 修改了显示
 */

#include <rtthread.h>
#include <rtdevice.h>
// STM32F1硬件头文件（根据实际MCU修改，如STM32F4需替换为stm32f4xx_hal.h）
#include "stm32f1xx_hal.h"
// 启用RT-Thread日志（可选，如需日志可保留）
#define RT_USING_LOG
#ifdef RT_USING_LOG
#include <rtdbg.h>
#endif

/* ------------------- LCD（ST7735）硬件引脚定义 ------------------- */
// 1. 软件SPI引脚（LCD专用，原共用逻辑已简化）
#define LCD_SCK_PIN        5    // PA5（SPI时钟）
#define LCD_SDA_PIN        7    // PA7（SPI发送：LCD的SDA）
// 2. LCD控制引脚
#define LCD_CS_PIN         4    // PA4（LCD片选，低电平有效）
#define LCD_RES_PIN        8    // PA8（LCD复位）
#define LCD_DC_PIN         31   // PB15（LCD数据/命令：16(GPIOB基址)+15=31）
#define LCD_BLK_PIN        30   // PB14（LCD背光：16+14=30）

/* ------------------- 高速GPIO寄存器操作（仅LCD相关） ------------------- */
// GPIOA寄存器（控制PA4/5/7/8）
#define GPIOA_BSRR         GPIOA->BSRR
#define GPIOA_IDR          GPIOA->IDR
// GPIOB寄存器（控制PB14/15）
#define GPIOB_BSRR         GPIOB->BSRR

/* ------------------- LCD引脚操作宏（简化版） ------------------- */
#define LCD_CS_HIGH        (GPIOA_BSRR = (1 << 4))    // PA4置高（取消选中）
#define LCD_CS_LOW         (GPIOA_BSRR = (1 << 4) << 16) // PA4置低（选中LCD）
#define LCD_SCK_HIGH       (GPIOA_BSRR = (1 << 5))    // PA5置高（SPI时钟高）
#define LCD_SCK_LOW        (GPIOA_BSRR = (1 << 5) << 16) // PA5置低（SPI时钟低）
#define LCD_SDA_HIGH       (GPIOA_BSRR = (1 << 7))    // PA7置高（SPI发送1）
#define LCD_SDA_LOW        (GPIOA_BSRR = (1 << 7) << 16) // PA7置低（SPI发送0）
#define LCD_RES_HIGH       (GPIOA_BSRR = (1 << 8))    // PA8置高（复位释放）
#define LCD_RES_LOW        (GPIOA_BSRR = (1 << 8) << 16) // PA8置低（复位触发）
#define LCD_DC_HIGH        (GPIOB_BSRR = (1 << 15))   // PB15置高（数据模式）
#define LCD_DC_LOW         (GPIOB_BSRR = (1 << 15) << 16) // PB15置低（命令模式）
#define LCD_BLK_HIGH       (GPIOB_BSRR = (1 << 14))   // PB14置高（背光开启）
#define LCD_BLK_LOW        (GPIOB_BSRR = (1 << 14) << 16) // PB14置低（背光关闭）

/* ------------------- LCD ST7735核心命令定义 ------------------- */
#define CMD_SOFT_RESET     0x01  // 软件复位
#define CMD_SLEEP_OUT      0x11  // 退出睡眠模式
#define CMD_COLOR_MODE     0x3A  // 颜色模式配置
#define CMD_MADCTL         0x36  // 显示方向配置
#define CMD_CASET          0x2A  // 列地址范围设置
#define CMD_RASET          0x2B  // 行地址范围设置
#define CMD_RAM_WR         0x2C  // 写入GRAM
#define CMD_DISPLAY_ON     0x29  // 开启显示
#define CMD_READ_ID        0x04  // 读取LCD ID（3字节）

/* ------------------- LCD RGB565颜色定义 ------------------- */
#define COLOR_BLACK        0x0000  // 黑色（背景默认）
#define COLOR_WHITE        0xFFFF  // 白色（文字默认）
#define COLOR_BLUE         0x001F  // 蓝色
#define COLOR_RED          0xF800  // 红色
#define COLOR_GREEN        0x07E0  // 绿色
#define COLOR_YELLOW       0xFFE0  // 黄色（标题用）
#define COLOR_CYAN         0x07FF  // 青色（数据用）

/* ------------------- 软件SPI核心函数（LCD专用，仅发送） ------------------- */
/**
 * @brief 软件SPI发送1bit数据（LCD仅需MOSI，无需读取MISO）
 * @param bit：要发送的bit（0/1）
 */
static void spi_send_bit(uint8_t bit) {
    // 先拉低SCK，准备数据
    LCD_SCK_LOW;
    rt_hw_us_delay(2);  // 延时确保稳定（可根据MCU主频调整）

    // 输出MOSI电平（1=高，0=低）
    bit ? LCD_SDA_HIGH : LCD_SDA_LOW;
    rt_hw_us_delay(2);

    // SCK上升沿，LCD采样数据
    LCD_SCK_HIGH;
    rt_hw_us_delay(2);
}

/**
 * @brief 软件SPI发送1字节数据
 * @param tx_data：要发送的字节（8bit）
 */
static void spi_send_byte(uint8_t tx_data) {
    // 高位先发送（ST7735要求）
    for (int i = 0; i < 8; i++) {
        spi_send_bit((tx_data & 0x80) ? 1 : 0);  // 取最高位
        tx_data <<= 1;  // 左移，准备下一位
    }
    LCD_SCK_LOW;  // 发送完成后拉低SCK
}

/* ------------------- LCD ST7735驱动核心函数 ------------------- */
/**
 * @brief LCD硬件复位（初始化前必须执行）
 */
static void lcd_reset(void) {
    LCD_RES_LOW;   // 触发复位
    rt_thread_mdelay(10);  // 复位延时（至少10ms）
    LCD_RES_HIGH;  // 释放复位
    rt_thread_mdelay(5);   // 等待LCD稳定
}

/**
 * @brief 发送LCD命令（DC=0）
 * @param cmd：ST7735命令码（如CMD_SLEEP_OUT）
 */
static void lcd_send_cmd(uint8_t cmd) {
    LCD_CS_LOW;          // 选中LCD
    LCD_DC_LOW;          // 切换为命令模式
    spi_send_byte(cmd);  // 发送命令
    LCD_CS_HIGH;         // 取消选中（单命令发送时）
}

/**
 * @brief 发送LCD数据（DC=1）
 * @param data：要写入的数据（如颜色值、地址值）
 */
static void lcd_send_data(uint8_t data) {
    LCD_CS_LOW;          // 选中LCD
    LCD_DC_HIGH;         // 切换为数据模式
    spi_send_byte(data); // 发送数据
    LCD_CS_HIGH;         // 取消选中（单数据发送时）
}

/**
 * @brief 连续发送多字节LCD数据（优化批量操作，如填充屏幕）
 * @param data：数据缓冲区
 * @param len：数据长度（字节数）
 */
static void lcd_send_data_burst(const uint8_t *data, uint32_t len) {
    if (data == RT_NULL || len == 0) return;

    LCD_CS_LOW;          // 选中LCD
    LCD_DC_HIGH;         // 数据模式
    for (uint32_t i = 0; i < len; i++) {
        spi_send_byte(data[i]);
    }
    LCD_CS_HIGH;         // 取消选中
}

/**
 * @brief 初始化ST7735 LCD（适配128×128分辨率）
 */
static void lcd_init(void) {
    // 1. 先复位LCD
    lcd_reset();

    // 2. 软件复位（确保寄存器初始化为默认值）
    lcd_send_cmd(CMD_SOFT_RESET);
    rt_thread_mdelay(5);  // 复位后等待稳定

    // 3. 退出睡眠模式（ST7735默认睡眠，需唤醒）
    lcd_send_cmd(CMD_SLEEP_OUT);
    rt_thread_mdelay(5);  // 唤醒后等待稳定

    // 4. 设置颜色模式：RGB565（16位色，0x05对应565格式）
    lcd_send_cmd(CMD_COLOR_MODE);
    lcd_send_data(0x05);
    rt_thread_mdelay(1);

    // 5. 设置显示方向：默认横向（0x00，可修改为0xC0实现垂直翻转）
    lcd_send_cmd(CMD_MADCTL);
    lcd_send_data(0x00);  // 0x00=正常，0xC0=上下翻转，0xA0=左右翻转
    rt_thread_mdelay(1);

    // 6. 设置列地址范围（128列：0~127）
    lcd_send_cmd(CMD_CASET);
    LCD_CS_LOW;  // 连续发送地址数据，保持CS低
    LCD_DC_HIGH;
    spi_send_byte(0x00); spi_send_byte(0x00);  // 起始列：0（高8位+低8位）
    spi_send_byte(0x00); spi_send_byte(0x7F);  // 结束列：127（0x7F）
    LCD_CS_HIGH;
    rt_thread_mdelay(1);

    // 7. 设置行地址范围（128行：0~127）
    lcd_send_cmd(CMD_RASET);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    spi_send_byte(0x00); spi_send_byte(0x00);  // 起始行：0
    spi_send_byte(0x00); spi_send_byte(0x7F);  // 结束行：127
    LCD_CS_HIGH;
    rt_thread_mdelay(1);

    // 8. 开启显示
    lcd_send_cmd(CMD_DISPLAY_ON);
    rt_thread_mdelay(5);

    // 9. 开启背光（默认关闭，需手动开启）
    LCD_BLK_HIGH;
#ifdef RT_USING_LOG
    LOG_I("LCD ST7735 init success (128x128)");
#endif
}

/**
 * @brief 填充整个LCD屏幕为指定颜色
 * @param color：RGB565颜色值（如COLOR_RED、0xF800）
 */
static void lcd_fill_screen(uint16_t color) {
    // 拆分颜色为高8位和低8位（RGB565格式）
    uint8_t color_buf[2] = {color >> 8, color & 0xFF};
    const uint32_t TOTAL_PIXEL = 128 * 128;  // 128x128总像素数
    const uint32_t TOTAL_BYTES = TOTAL_PIXEL * 2;  // 每个像素2字节

    // 设置GRAM写入地址（全屏幕范围）
    lcd_send_cmd(CMD_CASET);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    spi_send_byte(0x00); spi_send_byte(0x00);
    spi_send_byte(0x00); spi_send_byte(0x7F);
    LCD_CS_HIGH;

    lcd_send_cmd(CMD_RASET);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    spi_send_byte(0x00); spi_send_byte(0x00);
    spi_send_byte(0x00); spi_send_byte(0x7F);
    LCD_CS_HIGH;

    // 连续写入颜色数据（批量发送优化效率）
    lcd_send_cmd(CMD_RAM_WR);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    for (uint32_t i = 0; i < TOTAL_PIXEL; i++) {
        spi_send_byte(color_buf[0]);
        spi_send_byte(color_buf[1]);
    }
    LCD_CS_HIGH;
}

/**
 * @brief 绘制单个像素点（适配128×128分辨率）
 * @param x：列坐标（0~127，超出范围不绘制）
 * @param y：行坐标（0~127，超出范围不绘制）
 * @param color：RGB565颜色值
 */
static void lcd_draw_pixel(uint8_t x, uint8_t y, uint16_t color) {
    // 边界检查（避免超出屏幕范围）
    if (x > 127 || y > 127) return;

    // 设置单个像素的地址（x列，y行）
    lcd_send_cmd(CMD_CASET);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    spi_send_byte(0x00); spi_send_byte(x);  // 起始列=结束列=x
    spi_send_byte(0x00); spi_send_byte(x);
    LCD_CS_HIGH;

    lcd_send_cmd(CMD_RASET);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    spi_send_byte(0x00); spi_send_byte(y);  // 起始行=结束行=y
    spi_send_byte(0x00); spi_send_byte(y);
    LCD_CS_HIGH;

    // 写入像素颜色
    lcd_send_cmd(CMD_RAM_WR);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    spi_send_byte(color >> 8);
    spi_send_byte(color & 0xFF);
    LCD_CS_HIGH;
}

/* ------------------- 5×8 ASCII字模库（LCD字符显示依赖） ------------------- */
const uint8_t ascii_font[96][5] = {
    {0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 (空格)
    {0x00, 0x00, 0x5F, 0x00, 0x00}, // 0x21 (!)
    {0x00, 0x07, 0x00, 0x07, 0x00}, // 0x22 (")
    {0x14, 0x7F, 0x14, 0x7F, 0x14}, // 0x23 (#)
    {0x24, 0x2A, 0x7F, 0x2A, 0x12}, // 0x24 ($)
    {0x23, 0x13, 0x08, 0x64, 0x62}, // 0x25 (%)
    {0x36, 0x49, 0x55, 0x22, 0x50}, // 0x26 (&)
    {0x00, 0x05, 0x03, 0x00, 0x00}, // 0x27 (')
    {0x00, 0x1C, 0x22, 0x41, 0x00}, // 0x28 (()
    {0x00, 0x41, 0x22, 0x1C, 0x00}, // 0x29 ())
    {0x14, 0x08, 0x3E, 0x08, 0x14}, // 0x2A (*)
    {0x08, 0x08, 0x3E, 0x08, 0x08}, // 0x2B (+)
    {0x00, 0x50, 0x30, 0x00, 0x00}, // 0x2C (,)
    {0x08, 0x08, 0x08, 0x08, 0x08}, // 0x2D (-)
    {0x00, 0x60, 0x60, 0x00, 0x00}, // 0x2E (.)
    {0x20, 0x10, 0x08, 0x04, 0x02}, // 0x2F (/)
    {0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0x30 (0)
    {0x00, 0x42, 0x7F, 0x40, 0x00}, // 0x31 (1)
    {0x42, 0x61, 0x51, 0x49, 0x46}, // 0x32 (2)
    {0x21, 0x41, 0x45, 0x4B, 0x31}, // 0x33 (3)
    {0x18, 0x14, 0x12, 0x7F, 0x10}, // 0x34 (4)
    {0x27, 0x45, 0x45, 0x45, 0x39}, // 0x35 (5)
    {0x3C, 0x4A, 0x49, 0x49, 0x30}, // 0x36 (6)
    {0x01, 0x71, 0x09, 0x05, 0x03}, // 0x37 (7)
    {0x36, 0x49, 0x49, 0x49, 0x36}, // 0x38 (8)
    {0x06, 0x49, 0x49, 0x29, 0x1E}, // 0x39 (9)
    {0x00, 0x36, 0x36, 0x00, 0x00}, // 0x3A (:)
    {0x00, 0x56, 0x36, 0x00, 0x00}, // 0x3B (;)
    {0x00, 0x08, 0x14, 0x22, 0x41}, // 0x3C (<)
    {0x14, 0x14, 0x14, 0x14, 0x14}, // 0x3D (=)
    {0x00, 0x41, 0x22, 0x14, 0x08}, // 0x3E (>)
    {0x02, 0x01, 0x51, 0x09, 0x06}, // 0x3F (?)
    {0x32, 0x49, 0x79, 0x41, 0x3E}, // 0x40 (@)
    {0x7C, 0x12, 0x11, 0x12, 0x7C}, // 0x41 (A)
    {0x7F, 0x49, 0x49, 0x49, 0x36}, // 0x42 (B)
    {0x3E, 0x41, 0x41, 0x41, 0x22}, // 0x43 (C)
    {0x7F, 0x41, 0x41, 0x22, 0x1C}, // 0x44 (D)
    {0x7F, 0x49, 0x49, 0x49, 0x41}, // 0x45 (E)
    {0x7F, 0x09, 0x09, 0x09, 0x01}, // 0x46 (F)
    {0x3E, 0x41, 0x49, 0x49, 0x3A}, // 0x47 (G)
    {0x7F, 0x08, 0x08, 0x08, 0x7F}, // 0x48 (H)
    {0x00, 0x41, 0x7F, 0x41, 0x00}, // 0x49 (I)
    {0x20, 0x40, 0x41, 0x3F, 0x01}, // 0x4A (J)
    {0x7F, 0x08, 0x14, 0x22, 0x41}, // 0x4B (K)
    {0x7F, 0x40, 0x40, 0x40, 0x40}, // 0x4C (L)
    {0x7F, 0x02, 0x0C, 0x02, 0x7F}, // 0x4D (M)
    {0x7F, 0x04, 0x08, 0x10, 0x7F}, // 0x4E (N)
    {0x3E, 0x41, 0x41, 0x41, 0x3E}, // 0x4F (O)
    {0x7F, 0x09, 0x09, 0x09, 0x06}, // 0x50 (P)
    {0x3E, 0x41, 0x51, 0x21, 0x5E}, // 0x51 (Q)
    {0x7F, 0x09, 0x19, 0x29, 0x46}, // 0x52 (R)
    {0x46, 0x49, 0x49, 0x49, 0x31}, // 0x53 (S)
    {0x01, 0x01, 0x7F, 0x01, 0x01}, // 0x54 (T)
    {0x3F, 0x40, 0x40, 0x40, 0x3F}, // 0x55 (U)
    {0x1F, 0x20, 0x40, 0x20, 0x1F}, // 0x56 (V)
    {0x3F, 0x40, 0x38, 0x40, 0x3F}, // 0x57 (W)
    {0x63, 0x14, 0x08, 0x14, 0x63}, // 0x58 (X)
    {0x07, 0x08, 0x70, 0x08, 0x07}, // 0x59 (Y)
    {0x61, 0x51, 0x49, 0x45, 0x43}, // 0x5A (Z)
    {0x00, 0x7F, 0x41, 0x41, 0x00}, // 0x5B ([)
    {0x02, 0x04, 0x08, 0x10, 0x20}, // 0x5C (\)
    {0x00, 0x41, 0x41, 0x7F, 0x00}, // 0x5D (])
    {0x04, 0x02, 0x01, 0x02, 0x04}, // 0x5E (^)
    {0x40, 0x40, 0x40, 0x40, 0x40}, // 0x5F (_)
    {0x00, 0x01, 0x02, 0x04, 0x00}, // 0x60 (`)
    {0x20, 0x54, 0x54, 0x54, 0x78}, // 0x61 (a)
    {0x7F, 0x48, 0x44, 0x44, 0x38}, // 0x62 (b)
    {0x38, 0x44, 0x44, 0x44, 0x20}, // 0x63 (c)
    {0x38, 0x44, 0x44, 0x48, 0x7F}, // 0x64 (d)
    {0x38, 0x54, 0x54, 0x54, 0x18}, // 0x65 (e)
    {0x08, 0x7E, 0x09, 0x01, 0x02}, // 0x66 (f)
    {0x0C, 0x52, 0x52, 0x52, 0x3E}, // 0x67 (g)
    {0x7F, 0x08, 0x04, 0x04, 0x78}, // 0x68 (h)
    {0x00, 0x44, 0x7D, 0x40, 0x00}, // 0x69 (i)
    {0x20, 0x40, 0x44, 0x3D, 0x00}, // 0x6A (j)
    {0x7F, 0x10, 0x28, 0x44, 0x00}, // 0x6B (k)
    {0x00, 0x41, 0x7F, 0x40, 0x00}, // 0x6C (l)
    {0x7C, 0x04, 0x18, 0x04, 0x78}, // 0x6D (m)
    {0x7C, 0x08, 0x04, 0x04, 0x78}, // 0x6E (n)
    {0x38, 0x44, 0x44, 0x44, 0x38}, // 0x6F (o)
    {0x7C, 0x14, 0x14, 0x14, 0x08}, // 0x70 (p)
    {0x08, 0x14, 0x14, 0x18, 0x7C}, // 0x71 (q)
    {0x7C, 0x08, 0x04, 0x04, 0x08}, // 0x72 (r)
    {0x08, 0x54, 0x54, 0x54, 0x20}, // 0x73 (s)
    {0x04, 0x3F, 0x44, 0x40, 0x20}, // 0x74 (t)
    {0x3C, 0x40, 0x40, 0x20, 0x7C}, // 0x75 (u)
    {0x1C, 0x20, 0x40, 0x20, 0x1C}, // 0x76 (v)
    {0x3C, 0x40, 0x30, 0x40, 0x3C}, // 0x77 (w)
    {0x44, 0x28, 0x10, 0x28, 0x44}, // 0x78 (x)
    {0x0C, 0x50, 0x50, 0x50, 0x3C}, // 0x79 (y)
    {0x44, 0x64, 0x54, 0x4C, 0x44}, // 0x7A (z)
    {0x00, 0x08, 0x36, 0x41, 0x00}, // 0x7B ({)
    {0x00, 0x00, 0x7F, 0x00, 0x00}, // 0x7C (|)
    {0x00, 0x41, 0x36, 0x08, 0x00}, // 0x7D (})
    {0x10, 0x08, 0x08, 0x10, 0x08}, // 0x7E (~)
};

/**
 * @brief 绘制单个ASCII字符（5×8像素，支持空格~波浪号）
 * @param x：字符左上角列坐标（0~127）
 * @param y：字符左上角行坐标（0~127）
 * @param c：要显示的字符（ASCII 0x20~0x7E，超出范围显示空格）
 * @param color：字符颜色（RGB565）
 */
static void lcd_draw_char(uint8_t x, uint8_t y, char c, uint16_t color) {
    // 计算字模索引（ASCII 0x20对应索引0，0x7E对应索引95）
    uint8_t idx = c - 0x20;
    if (idx >= 96) idx = 0;  // 超出范围显示空格

    const uint8_t *font = ascii_font[idx];
    // 遍历5列字模（宽度）和8行像素（高度）
    for (int col = 0; col < 5; col++) {
        for (int row = 0; row < 8; row++) {
            // 字模中bit为1的位置绘制像素
            if (font[col] & (1 << row)) {
                lcd_draw_pixel(x + col, y + row, color);
            }
        }
    }
}

/**
 * @brief 在LCD指定位置显示字符串（自动换行前不超出屏幕）
 * @param x：字符串左上角列坐标（0~127）
 * @param y：字符串左上角行坐标（0~127）
 * @param str：要显示的字符串（NULL结尾）
 * @param color：字符串颜色（RGB565）
 */
static void lcd_draw_string(uint8_t x, uint8_t y, const char *str, uint16_t color) {
    if (str == RT_NULL) return;

    uint8_t curr_x = x;  // 当前列坐标（逐字符递增）
    while (*str != '\0') {
        // 边界检查：字符右侧不超出屏幕，字符底部不超出屏幕
        if (curr_x > 127 - 5 || y > 127 - 8) break;

        lcd_draw_char(curr_x, y, *str, color);
        curr_x += 7;  // 字符间距：5列字模 + 2列空白（避免字符重叠）
        str++;
    }
}

/**
 * @brief 清除LCD指定矩形区域（填充背景色）
 * @param x1：区域左上角列坐标（0~127）
 * @param x2：区域右下角列坐标（0~127，需≥x1）
 * @param y1：区域左上角行坐标（0~127）
 * @param y2：区域右下角行坐标（0~127，需≥y1）
 * @param bg_color：背景色（RGB565，如COLOR_BLACK）
 */
static void lcd_clear_area(uint8_t x1, uint8_t x2, uint8_t y1, uint8_t y2, uint16_t bg_color) {
    if (x1 > x2 || y1 > y2) return;  // 无效区域直接返回

    // 拆分颜色为高低字节
    uint8_t color_h = bg_color >> 8;
    uint8_t color_l = bg_color & 0xFF;
    // 计算区域总像素数和总字节数
    uint32_t pixel_cnt = (x2 - x1 + 1) * (y2 - y1 + 1);

    // 设置清除区域的地址范围
    lcd_send_cmd(CMD_CASET);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    spi_send_byte(0x00); spi_send_byte(x1);
    spi_send_byte(0x00); spi_send_byte(x2);
    LCD_CS_HIGH;

    lcd_send_cmd(CMD_RASET);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    spi_send_byte(0x00); spi_send_byte(y1);
    spi_send_byte(0x00); spi_send_byte(y2);
    LCD_CS_HIGH;

    // 填充背景色
    lcd_send_cmd(CMD_RAM_WR);
    LCD_CS_LOW;
    LCD_DC_HIGH;
    for (uint32_t i = 0; i < pixel_cnt; i++) {
        spi_send_byte(color_h);
        spi_send_byte(color_l);
    }
    LCD_CS_HIGH;
}

/**
 * @brief 读取ST7735的3字节ID（用于验证LCD通信）
 * @param id_buf：接收ID的缓冲区（需至少3字节空间）
 * @return 0=读取成功，1=读取失败（缓冲区NULL）
 */
static int lcd_read_id(uint8_t *id_buf) {
    if (id_buf == RT_NULL) return 1;

    LCD_CS_LOW;
    LCD_DC_LOW;          // 命令模式：发送读ID命令
    spi_send_byte(CMD_READ_ID);
    LCD_DC_HIGH;         // 数据模式：接收ID数据

    // ST7735读ID返回3字节：制造商ID（1字节）+ 驱动IC ID（2字节）
    id_buf[0] = 0;  // 读取占位（部分ST7735首字节为 dummy，需根据实际型号调整）
    for (int i = 0; i < 3; i++) {
        // 读数据时需发送0xFF（软件SPI双向通信）
        uint8_t dummy = 0xFF;
        for (int j = 0; j < 8; j++) {
            spi_send_bit((dummy & 0x80) ? 1 : 0);
            dummy <<= 1;
            // 读取MISO电平（需启用PA6为输入，原代码中已注释，此处补充）
            if (j == 7) {
                id_buf[i] = (GPIOA_IDR & (1 << 6)) ? (dummy | 0x01) : dummy;
            }
        }
    }

    LCD_CS_HIGH;
    return 0;
}

/* ------------------- LCD测试主线程（RT-Thread） ------------------- */
static void lcd_test_thread(void *param) {
    uint8_t lcd_id[3] = {0};
    char lcd_id_str[30] = {0};
    uint8_t test_cnt = 0;  // 测试计数（用于动态显示）

    // 1. 初始化LCD所有引脚为输出模式
    rt_pin_mode(LCD_CS_PIN,    PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_SCK_PIN,   PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_SDA_PIN,   PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_RES_PIN,   PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_DC_PIN,    PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_BLK_PIN,   PIN_MODE_OUTPUT);
    // 初始化PA6为输入（读取LCD ID时用）
    rt_pin_mode(6, PIN_MODE_INPUT);

    // 2. 引脚初始电平（避免不确定状态）
    LCD_CS_HIGH;    // 未选中LCD
    LCD_SCK_LOW;    // SPI时钟默认低
    LCD_SDA_LOW;    // SPI发送默认低
    LCD_RES_HIGH;   // 复位默认释放
    LCD_DC_LOW;     // 默认命令模式
    LCD_BLK_LOW;    // 背光默认关闭

    // 3. 初始化LCD
    lcd_init();
    // 填充黑色背景
    lcd_fill_screen(COLOR_BLACK);
    rt_thread_mdelay(500);

    // 4. 读取并显示LCD ID
    if (lcd_read_id(lcd_id) == 0) {
        rt_sprintf(lcd_id_str, "LCD ID: 0x%02X 0x%02X 0x%02X",
                   lcd_id[0], lcd_id[1], lcd_id[2]);
        lcd_draw_string(10, 15, "ST7735 Info:", COLOR_YELLOW);  // 标题
        lcd_draw_string(10, 30, lcd_id_str, COLOR_WHITE);       // ID信息
        lcd_draw_string(10, 45, "Resolution: 128x128", COLOR_GREEN); // 分辨率
#ifdef RT_USING_LOG
        LOG_I("LCD ID: 0x%02X, 0x%02X, 0x%02X", lcd_id[0], lcd_id[1], lcd_id[2]);
#endif
    } else {
        lcd_draw_string(10, 15, "LCD ID Read Err!", COLOR_RED);  // 错误提示
#ifdef RT_USING_LOG
        LOG_E("LCD ID read failed (buffer NULL)");
#endif
    }

    // 5. 循环显示测试内容（动态更新）
    while (1) {
        char test_str[20] = {0};
        // 清除旧的测试内容区域（避免重叠）
        lcd_clear_area(10, 127, 65, 95, COLOR_BLACK);

        // 动态生成测试字符串（计数+颜色切换）
        rt_sprintf(test_str, "Test Count: %d", test_cnt++);
        // 每隔5次切换颜色（红→蓝→青→绿→黄）
        switch (test_cnt % 5) {
            case 0: lcd_draw_string(10, 65, test_str, COLOR_RED); break;
            case 1: lcd_draw_string(10, 65, test_str, COLOR_BLUE); break;
            case 2: lcd_draw_string(10, 65, test_str, COLOR_CYAN); break;
            case 3: lcd_draw_string(10, 65, test_str, COLOR_GREEN); break;
            case 4: lcd_draw_string(10, 65, test_str, COLOR_YELLOW); break;
        }

        // 显示固定提示
        lcd_draw_string(10, 85, "RT-Thread LCD Test", COLOR_WHITE);
        rt_thread_mdelay(1000);  // 1秒刷新一次
    }
}

/* ------------------- RT-Thread自动初始化（应用层） ------------------- */
static int lcd_test_init(void) {
    // 创建LCD测试线程（栈大小2048字节，中等优先级）
    rt_thread_t tid = rt_thread_create(
        "lcd_st7735_test",  // 线程名
        lcd_test_thread,    // 线程函数
        RT_NULL,            // 线程参数（无）
        2048,               // 栈大小（字节）
        RT_THREAD_PRIORITY_MAX / 2,  // 优先级（中等）
        20                  // 时间片（tick）
    );

    if (tid != RT_NULL) {
        rt_thread_startup(tid);  // 启动线程
#ifdef RT_USING_LOG
        LOG_I("LCD test thread created (name: lcd_st7735_test)");
#endif
    } else {
#ifdef RT_USING_LOG
        LOG_E("LCD test thread create failed (stack/heap full)");
#endif
    }
    return 0;
}

// RT-Thread自动初始化：系统启动后执行lcd_test_init（应用层优先级）
INIT_APP_EXPORT(lcd_test_init);
